﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public static class MeshGenerator {
    #region 自定义函数
    public static MeshData GenerateTerrainMesh (float[, ] heightMap, AnimationCurve _heightCurve, float heightMultiplier, int levelOfDetail) {
        AnimationCurve heightCurve = new AnimationCurve (_heightCurve.keys);
        // 获取高度图的宽和高
        int width = heightMap.GetLength (0);
        int height = heightMap.GetLength (1);

        // 相对于中心点左上角的xy的坐标（用于让mesh位于中心）
        float topLeftX = (width - 1) / -2f;
        float topLeftZ = (height - 1) / 2f;

        // 计算生成LOD所用的步长和顶点数量
        int meshSimplificationIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2; // 简化数量
        int verticesPerLine = (width - 1) / meshSimplificationIncrement + 1; // 每行顶点的数量 原理看视频中四分钟最有的计算https://www.youtube.com/watch?v=417kJGPKwDg&list=PLFt_AvWsXl0eBW2EiBtl_sxmDtSgZBxB3&index=7&t=53s

        // mesh数据
        MeshData meshData = new MeshData (verticesPerLine, verticesPerLine);
        int vertexIndex = 0;

        // 遍历所有点
        for (int y = 0; y < height; y += meshSimplificationIncrement) {
            for (int x = 0; x < width; x += meshSimplificationIncrement) {
                // 设置顶点位置
                meshData.vertices[vertexIndex] = new Vector3 (topLeftX + x, heightMap[x, y] * heightMultiplier * heightCurve.Evaluate (heightMap[x, y]), topLeftZ - y);
                // 设置uv
                meshData.uvs[vertexIndex] = new Vector2 (x / (float) width, y / (float) height);

                // 按顺时针顶点顺序添加三角面（一次加两个，最右和最下一排顶点不用管）
                if (x < width - 1 && y < height - 1) {
                    meshData.AddTriangle (vertexIndex, vertexIndex + verticesPerLine + 1, vertexIndex + verticesPerLine);
                    meshData.AddTriangle (vertexIndex + verticesPerLine + 1, vertexIndex, vertexIndex + 1);
                }
                // 到下一个顶点
                vertexIndex++;
            }
        }
        // 为什么返回MeshData而不直接返回Mesh是有原因的
        // 具体原因看https://www.youtube.com/watch?v=4RpVBYW1r5M&list=PLFt_AvWsXl0eBW2EiBtl_sxmDtSgZBxB3&index=5 中12:10左右的讲解
        return meshData;
    }
    #endregion
}

/// <summary>
///  存储Mesh数据的类 
/// </summary>
public class MeshData {
    public Vector3[] vertices; // 顶点
    public int[] triangles; // 三角面
    int triangleIndex; // 三角面索引
    public Vector2[] uvs; // uv
    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="meshWidth">宽</param>
    /// <param name="meshHeight">高</param>
    public MeshData (int meshWidth, int meshHeight) {
        // 通过宽和高计算顶点和三角面数，公式来源看https://www.youtube.com/watch?v=4RpVBYW1r5M&list=PLFt_AvWsXl0eBW2EiBtl_sxmDtSgZBxB3&index=6&t=0s
        vertices = new Vector3[meshWidth * meshHeight];
        uvs = new Vector2[meshWidth * meshHeight];
        triangles = new int[(meshWidth - 1) * (meshHeight - 1) * 6];
    }

    /// <summary>
    /// 添加一个三角面
    /// </summary>
    /// <param name="a"></param>
    /// <param name="b"></param>
    /// <param name="c"></param>
    public void AddTriangle (int a, int b, int c) {
        triangles[triangleIndex] = a;
        triangles[triangleIndex + 1] = b;
        triangles[triangleIndex + 2] = c;
        triangleIndex += 3;
    }

    /// <summary>
    /// 根据数据生成mesh
    /// </summary>
    /// <returns>生成的mesh</returns>
    public Mesh CreatMesh () {
        Mesh mesh = new Mesh ();
        mesh.vertices = vertices;
        mesh.triangles = triangles;
        mesh.uv = uvs;
        mesh.RecalculateNormals ();
        return mesh;
    }
}